package com.example.my.widget;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ScaleGestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.OverScroller;

import com.example.my.R;

public class TestView extends View implements GestureDetector.OnGestureListener, Runnable {
    private static final int IMAGE_SIZE = 400;
    private static final float EXTRA_SCALE_FACTOR = 1.2f;
    private Paint paint;
    private Bitmap bitmap;
    private float originalOffsetX;
    private float originalOffsetY;
    private float offsetX;
    private float offsetY;
    private float smallScale;
    private float bigScale;
    private GestureDetectorCompat gestureDetectorCompat;
    private ScaleGestureDetector scaleGestureDetector;
    private MyScaleGestureListener scaleGestureListener;
    private boolean big;
    private float scaleFraction;
    private ObjectAnimator scaleAnimator;
    private OverScroller overScroller;


    public TestView(Context context) {
        this(context, null);
    }

    public TestView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }


    /**
     * 初始化
     */
    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);

        bitmap = getBitmap(IMAGE_SIZE);

        gestureDetectorCompat = new GestureDetectorCompat(getContext(), this);
        gestureDetectorCompat.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                Log.e("TestView", "onSingleTapConfirmed");
                return false;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.e("TestView", "onDoubleTap");
                big = !big;
                if (big) {


                    scaleAnimator.start();
                } else {
                    scaleAnimator.reverse();
                }
                return true;
            }

            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                Log.e("TestView", "onDoubleTapEvent");
                return false;
            }
        });

        scaleAnimator = ObjectAnimator.ofFloat(this, "scaleFraction", 0f, 1f).setDuration(1000);
        scaleAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                offsetX = 0;
                offsetY = 0;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        overScroller = new OverScroller(getContext());

        scaleGestureListener = new MyScaleGestureListener();
        scaleGestureDetector = new ScaleGestureDetector(getContext(), scaleGestureListener);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        originalOffsetX = (getWidth() - IMAGE_SIZE) / 2;
        originalOffsetY = (getHeight() - IMAGE_SIZE) / 2;

        if (Float.valueOf(bitmap.getWidth() / bitmap.getHeight()) > Float.valueOf(getWidth() / getHeight())) {
            smallScale = getWidth() / bitmap.getWidth();
            bigScale = getHeight() / bitmap.getHeight() * EXTRA_SCALE_FACTOR;
        } else {
            smallScale = getHeight() / bitmap.getHeight();
            bigScale = getWidth() / bitmap.getWidth() * EXTRA_SCALE_FACTOR;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TestView", "onTouchEvent");
        scaleGestureDetector.onTouchEvent(event);
        if (!scaleGestureDetector.isInProgress()) {
            gestureDetectorCompat.onTouchEvent(event);
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.translate(offsetX * scaleFraction, offsetY * scaleFraction);

        float scale = smallScale + (bigScale - smallScale) * scaleFraction;
        canvas.scale(scale, scale, getWidth() / 2, getHeight() / 2);


        canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint);
    }

    /**
     * 加载图片
     *
     * @param width 图片宽高
     * @return Bitmap
     */
    private Bitmap getBitmap(int width) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), R.drawable.icon_user, options);

        options.inJustDecodeBounds = false;
        options.inDensity = options.outWidth;
        options.inTargetDensity = width;

        return BitmapFactory.decodeResource(getResources(), R.drawable.icon_user, options);

    }

    @Override
    public boolean onDown(MotionEvent e) {
        Log.e("TestView", "onDown");
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        Log.e("TestView", "onShowPress");
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Log.e("TestView", "onSingleTapUp");
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.e("TestView", "onScroll");
        if (big) {
            offsetX -= distanceX;
            offsetY -= distanceY;
            offsetX = Math.min(offsetX, (bitmap.getWidth() * bigScale - getWidth()) / 2);
            offsetX = Math.max(offsetX, -(bitmap.getWidth() * bigScale - getWidth()) / 2);

            offsetY = Math.min(offsetY, (bitmap.getHeight() * bigScale - getHeight()) / 2);
            offsetY = Math.max(offsetY, -(bitmap.getHeight() * bigScale - getHeight()) / 2);

            invalidate();
        }
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Log.e("TestView", "onLongPress");
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        Log.e("TestView", "onFling");
        if (big) {
            overScroller.fling((int) offsetX,
                    (int) offsetY,
                    (int) velocityX,
                    (int) velocityY,
                    -(int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                    (int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                    -(int) (bitmap.getHeight() * bigScale - getHeight()) / 2,
                    (int) (bitmap.getHeight() * bigScale - getHeight()) / 2,
                    100,
                    100
            );

            ViewCompat.postOnAnimation(TestView.this, this);
        }
        return true;
    }

    public void setScaleFraction(float scaleFraction) {
        this.scaleFraction = scaleFraction;
        invalidate();
    }

    @Override
    public void run() {
        if (overScroller.computeScrollOffset()) {
            offsetX = overScroller.getCurrX();
            offsetY = overScroller.getCurrY();
            invalidate();

            ViewCompat.postOnAnimation(TestView.this, this);
        }
    }

    /**
     * 手势缩放监听
     */
    public class MyScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            return false;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return false;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {

        }
    }
}
